#ifndef _STACK_H_
#define _STACK_H_

/*****************************************************************************/
/**********					Stack class declaration					**********/
/*****************************************************************************/
//Basic generic stack implementation using an array

#include "Exceptions.h"
#include <cassert>

namespace DataStructuresWet1
{

template <class DataT>
class Stack
{
	/*************************************************/
	/**********			Public members			******/
	/*************************************************/
public:
	//Ctor
	Stack(int maxSize);
	//Copy ctor
	Stack(Stack<DataT>& other);
	//Dtor
	~Stack();
	//Pushes an element to the stack
	void Push(DataT* data);
	//Pops the top element from the stak
	DataT* Pop();
	//Peek to the top element without popping it
	DataT* Peek();
	//Size of stack
	int Size();
	//Maximum size of stack
	int MaxSize();
	/*************************************************/
	/**********		Protected members			******/
	/*************************************************/
protected:
	//Data members:
	DataT** arr;
	int maxSize;
	int pos;
};

/*************************************************/
/*****	Class implementation members		******/
/*************************************************/
template <class DataT>
Stack<DataT>::Stack(int maxSize) : arr(new DataT*[maxSize]), maxSize(maxSize), pos(-1){}

template <class DataT>
Stack<DataT>::Stack(Stack<DataT>& other) : maxSize(other.MaxSize), pos(other.pos)
{
	memcpy(this->arr, other.arr, maxSize * sizeof(DataT*));
}

template <class DataT>
Stack<DataT>::~Stack()
{
	delete [] arr;
}

template <class DataT>
void Stack<DataT>::Push(DataT* data)
{
	//Validate that there is room
	if (pos >= maxSize - 1)
	{
		throw FailureException();
	}
	//Insert data to array and increment current position
	arr[++pos] = data;
}

template <class DataT>
DataT* Stack<DataT>::Pop()
{
	assert(pos>=-1);
	//Top position, stack is empty
	if (pos == -1)
	{
		return NULL;
	}
	//Retrieve last element in the stack and decrement position
	return arr[pos--];
}

template <class DataT>
DataT* Stack<DataT>::Peek()
{
	//Top position, stack is empty
	if (pos == -1)
	{
		return NULL;
	}
	//Retrieve last element in the stack
	return arr[pos];
}

template <class DataT>
int Stack<DataT>::Size()
{
	return pos+1;
}

template <class DataT>
int Stack<DataT>::MaxSize()
{
	return maxSize;
}

} //DataStructuresWet1

#endif //_STACK_H_
